from django.http import JsonResponse, HttpResponse
from django.views.decorators.http import require_http_methods
import json
import re
import datetime

from shapely import LineString
from sklearn.ensemble import IsolationForest

from aileakage.Pipe import Pipe
from aileakage.WaterSupplyArea import generate_water_supply_area


# 接口1：管网风险等级 /api/ai-leakage/link/risk-level
@require_http_methods(["POST"])
def risk_level_view(request):
    try:
        # 获取 POST 请求中的 JSON 数据
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON data"}, status=400)

        if isinstance(data, list):
            pipes = []
            for item in data:
                pipe = Pipe(
                    id=item['id'],
                    diameter=item['diameter'],
                    material=item['material'],
                    pressure=item['pressure']
                )
                pipes.append(pipe)
            result = Pipe.risk_level_cal(pipes)  # 修改为调用类方法
            return JsonResponse({"data": result}, status=200)
        else:
            return JsonResponse({"error": "Invalid data format"}, status=400)
    except Exception as e:
        return JsonResponse({"error": str(e)}, status=500)


# 接口2：基于年龄的风险评估 /api/ai-leakage/age-risk
@require_http_methods(["POST"])
def age_based_risk_view(request):
    try:
        # 获取 POST 请求中的 JSON 数据
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON data"}, status=400)

        if isinstance(data, list):
            pipes = []
            for item in data:
                pipe = Pipe(
                    id=item['id'],
                    material=item['material'],
                    installation_year=item['installation_year'],
                    pressure_score=item['pressure_score']
                )
                pipes.append(pipe)
            result = Pipe.age_based_risk(pipes)
            return JsonResponse({"data": result}, status=200)
        else:
            return JsonResponse({"error": "Invalid data format"}, status=400)
    except Exception as e:
        return JsonResponse({"error": str(e)}, status=500)


# 接口3：智能调压 /api/ai-leakage/pressure-ctrl
@require_http_methods(["POST"])
def smart_pressure_control_view(request):
    try:
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON data"}, status=400)

        if isinstance(data, list):
            pipes = []
            for item in data:
                pipe = Pipe(
                    id=item['id'],
                    time=item['time'],
                    pressure=item['pressure']
                )
                pipes.append(pipe)
            result = Pipe.smart_pressure_control(pipes)
            return JsonResponse({"data": result}, status=200)
        else:
            return JsonResponse({"error": "Invalid data format"}, status=400)
    except Exception as e:
        return JsonResponse({"error": str(e)}, status=500)


# 接口4：爆管预测 /api/ai-leakage/pipe-burst
@require_http_methods(["POST"])
def detect_pipe_burst_view(request):
    try:
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON data"}, status=400)

        if isinstance(data, list):
            pipes = []
            for item in data:
                pipe = Pipe(
                    id=item['time'],
                    time=item['time'],
                    pressure=item['pressure'],
                    flow=item['flow'],
                    demand=item['demand']
                )
                pipes.append(pipe)
            result = Pipe.detect_pipe_burst(pipes)
            return JsonResponse({"data": result}, status=200)
        else:
            return JsonResponse({"error": "Invalid data format"}, status=400)
    except Exception as e:
        return JsonResponse({"error": str(e)}, status=500)


# 接口5：压力瞬变报警 /api/ai-leakage/pressure-anomaly
@require_http_methods(["POST"])
def detect_pressure_anomaly_view(request):
    try:
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON data"}, status=400)

        if isinstance(data, list):
            pipes = []
            for item in data:
                pipe = Pipe(
                    time=item['time'],
                    pressure=item['pressure']
                )
                pipes.append(pipe)
            result = Pipe.detect_pressure_anomaly(pipes)
            return JsonResponse({"data": result}, status=200)
        elif isinstance(data, dict):
            # 如果是字典，传的multi iot 监测数据，多个数倍数据
            result_dict = {}
            for key, val in data.items():
                pipes = []
                for item in val:
                    pipe = Pipe(
                        time=item['time'],
                        pressure=item['pressure']
                    )
                    pipes.append(pipe)
                result = Pipe.detect_pressure_anomaly(pipes)
                if result is not None:
                    result_dict[key] = result
            return JsonResponse({"data": result_dict}, status=200)
        else:
            return JsonResponse({"error": "Invalid data format"}, status=400)
    except Exception as e:
        return JsonResponse({"error": str(e)}, status=500)


# 接口6：压力瞬变报警:基于孤立森林-检测异常数据算法 /api/ai-leakage/pressure-anomaly-forest
@require_http_methods(["POST"])
def pressure_anomaly_forest_view(request):
    try:
        # 获取 POST 请求中的 JSON 数据
        try:
            data = json.loads(request.body)
        except json.JSONDecodeError:
            return JsonResponse({"error": "Invalid JSON data"}, status=400)

        # 初始化结果字典
        res = {}

        # 遍历每个设备 ID
        for device_id, time_pressure_map in data.items():
            # 提取时间和压力数据, 转换为适合孤立森林模型的格式
            time_pressure_list = [(record["time"], record["pressure"]) for record in time_pressure_map]
            if len(time_pressure_list) < 12:
                continue
            train_data = [[pressure] for _, pressure in time_pressure_list[:-1]]
            test_data = [[pressure] for _, pressure in time_pressure_list[-1:]]
            test_times = [time for time, _ in time_pressure_list[-1:]]

            # 创建并训练孤立森林模型
            model = IsolationForest(n_estimators=100, contamination=0.1)  # 可以根据实际情况调整 contamination 参数
            model.fit(train_data)

            # 对检测数据进行异常检测
            predictions = model.predict(test_data)

            # 找出异常值
            anomaly_map = {}
            for i, prediction in enumerate(predictions):
                if prediction == -1:
                    # anomaly_map[test_times[i]] = time_pressure_list[-len(test_times):][i][1]
                    anomaly_map["time"] = test_times[i]
                    anomaly_map["pressure"] = round(time_pressure_list[-len(test_times):][i][1], 3)

            # 如果有异常值，将其添加到结果字典中
            if anomaly_map:
                res[device_id] = anomaly_map

        return JsonResponse({"data": res}, status=200)

    except Exception as e:
        return JsonResponse({"error": str(e)}, status=500)


# 接口7：缓冲区生成 /api/ai-leakage/burst-affect-buffer
@require_http_methods(["POST"])
def burst_affect_buffer_view(request):
    try:
        data = json.loads(request.body)
        pipe_lines = []
        for link in data:
            # 提取坐标部分
            geowkt = link.get("geowkt")
            if not isinstance(geowkt, str):
                print(f"Warning: geowkt is not a string in {link}")
                continue
            # 使用正则表达式提取坐标部分（忽略LINESTRING后的空格，处理各种格式）
            match = re.search(r'^LINESTRING\s*\((.+)\)$', geowkt.strip(), re.IGNORECASE)
            if not match:
                print(f"Warning: Invalid LINESTRING format in {geowkt}")
                continue
            coords_str = match.group(1)
            try:
                # 分割坐标对并转换为浮点数
                coords_list = coords_str.split(",")
                coords = []

                for coord in coords_list:
                    parts = coord.strip().split()
                    if len(parts) != 2:
                        raise ValueError(f"Invalid coordinate format: {coord}")
                    x, y = map(float, parts)
                    coords.append((x, y))
                if len(coords) < 2:
                    raise ValueError("At least two points are required to form a LineString")
                # 创建LineString对象
                line = LineString(coords)
                pipe_lines.append(line)
            except (ValueError, TypeError) as e:
                print(f"Warning: Failed to parse coordinates in {geowkt}: {str(e)}")
        buffer_radius = 0.0003  # 根据你的数据规模调整

        # 生成供水区域
        water_supply_area = generate_water_supply_area(pipe_lines, buffer_radius)

        if water_supply_area:
            data = {
                'area': water_supply_area.area,
                'geowkt': water_supply_area.wkt
            }
            return JsonResponse({"data": data}, status=200)
        else:
            return JsonResponse({'error': '未能生成供水区域，可能是输入数据为空。'}, status=400)
    except Exception as e:
        return JsonResponse({'error': str(e)}, status=500)
